package sf.database.util;

import sf.core.DBField;
import sf.core.DBObject;
import sf.database.dao.DBContext;
import sf.database.meta.ColumnMapping;
import sf.database.meta.MetaHolder;
import sf.database.meta.TableMapping;
import sf.spring.util.Assert;
import sf.spring.util.ReflectionUtils;
import sf.tools.StringUtils;

import javax.persistence.PersistenceException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class OrmUtils {
    /**
     * 填充非空值到map中
     */
    public static void fillNotNullValue(DBObject obj) {
        obj.newUpdate();
        OrmUtils.getDataObjectNotNullValue(obj, obj.updateValueMap());
    }

    /**
     * 获取非null的Map
     * @param obj
     * @return
     */
    public static Map<DBField, Object> getDataObjectNotNullValue(DBObject obj, Map<DBField, Object> map) {
        if (map == null) {
            map = new HashMap<>();
        }
        TableMapping table = MetaHolder.getMeta(obj.getClass());
        for (Map.Entry<DBField, ColumnMapping> entry : table.getSchemaMap().entrySet()) {
            ColumnMapping cm = entry.getValue();
            if (cm != null) {
                Object value = OrmValueUtils.getValue(obj, cm);
                if (value != null) {
                    map.put(entry.getKey(), value);
                }
            }
        }
        return map;
    }

    /**
     * 获取值
     * @param obj
     * @param fields
     * @return
     */
    public static Object[] getDataObjectValues(DBObject obj, DBField... fields) {
        TableMapping table = MetaHolder.getMeta(obj.getClass());
        Object[] values = new Object[fields.length];
        int i = 0;
        for (DBField field : fields) {
            ColumnMapping cm = table.getSchemaMap().get(field);
            if (cm != null) {
                values[i] = OrmValueUtils.getValue(obj, cm);
            }
            i++;
        }
        return values;
    }

    /**
     * 获取值
     * @param obj
     * @param field
     * @return
     */
    public static Object getDataObjectValue(DBObject obj, DBField field) {
        TableMapping table = MetaHolder.getMeta(obj.getClass());
        Object value = null;
        ColumnMapping cm = table.getSchemaMap().get(field);
        if (cm != null) {
            value = OrmValueUtils.getValue(obj, cm);
        }
        return value;
    }

    public static Object getDataObjectValue(DBObject obj, Field f) {
        Object value = null;
        if (!f.isAccessible()) {
            f.setAccessible(true);
        }
        value = ReflectionUtils.getField(f, obj);
        return value;
    }

    public static Object getDataObjectValue(DBObject obj, String field) {
        TableMapping table = MetaHolder.getMeta(obj.getClass());
        DBField dbField = table.getFields().get(field);
        Object value = getDataObjectValue(obj, dbField);
        return value;
    }

    /**
     * 设置指定的值到主键
     * @param data 对象
     * @param pk   主键，可以是数组或单值
     */
    public static void setPrimaryKeyValue(DBObject data, Object pk) throws PersistenceException {
        List<ColumnMapping> fields = MetaHolder.getMeta(data.getClass()).getPkFields();
        if (fields.isEmpty())
            return;
        Assert.notNull(pk, "");
        if (pk.getClass().isArray()) {
            int length = Array.getLength(pk);
            int n = 0;
            Assert.isTrue(length == fields.size(), "");
            for (ColumnMapping f : fields) {
                f.getFieldAccessor().set(data, Array.get(pk, n++));
            }
        } else {
            if (fields.size() != 1) {
                throw new PersistenceException("No Proper PK fields!");
            }
            fields.get(0).getFieldAccessor().set(data, pk);
        }
    }

    /**
     * 提供主键的值
     */
    public static Map<String, Object> getPrimaryKeyValueMap(DBObject data) {
        TableMapping meta = MetaHolder.getMeta(data.getClass());
        int len = meta.getPkFields().size();
        if (len == 0)
            return null;
        Map<String, Object> keyValMap = new HashMap<String, Object>();
        for (int i = 0; i < len; i++) {
            ColumnMapping field = meta.getPkFields().get(i);
            keyValMap.put(field.getFieldName(), field.getFieldAccessor().get(data));
        }
        return keyValMap;
    }

    /**
     * 提供主键的值
     */
    public static List<Object> getPrimaryKeyValue(DBObject data) {
        TableMapping meta = MetaHolder.getMeta(data.getClass());
        if (meta.getPkFields().isEmpty())
            return null;

        int len = meta.getPkFields().size();
        Object[] result = new Object[len];
        for (int i = 0; i < len; i++) {
            ColumnMapping field = meta.getPkFields().get(i);
            result[i] = field.getFieldAccessor().get(data);
        }
        return Arrays.asList(result);
    }

    /**
     * 获取动态表名
     * @param context
     * @param tableMapping
     * @return
     */
    public static String getDynamicTableName(DBContext context, TableMapping tableMapping) {
        if (context != null && StringUtils.isNotBlank(context.getDynamicTableName())) {
            return context.getDynamicTableName();
        }
        return tableMapping.getTableName();
    }

    public static String getDynamicTableName(DBContext context) {
        if (context != null && StringUtils.isNotBlank(context.getDynamicTableName())) {
            return context.getDynamicTableName();
        }
        return null;
    }
}
